-- C390007.A
--
--                             Grant of Unlimited Rights
--
--     Under contracts F33600-87-D-0337, F33600-84-D-0280, MDA903-79-C-0687,
--     F08630-91-C-0015, and DCA100-97-D-0025, the U.S. Government obtained 
--     unlimited rights in the software and documentation contained herein.
--     Unlimited rights are defined in DFAR 252.227-7013(a)(19).  By making 
--     this public release, the Government intends to confer upon all 
--     recipients unlimited rights  equal to those held by the Government.  
--     These rights include rights to use, duplicate, release or disclose the 
--     released technical data and computer software in whole or in part, in 
--     any manner and for any purpose whatsoever, and to have or permit others 
--     to do so.
--
--                                    DISCLAIMER
--
--     ALL MATERIALS OR INFORMATION HEREIN RELEASED, MADE AVAILABLE OR
--     DISCLOSED ARE AS IS.  THE GOVERNMENT MAKES NO EXPRESS OR IMPLIED 
--     WARRANTY AS TO ANY MATTER WHATSOEVER, INCLUDING THE CONDITIONS OF THE
--     SOFTWARE, DOCUMENTATION OR OTHER INFORMATION RELEASED, MADE AVAILABLE 
--     OR DISCLOSED, OR THE OWNERSHIP, MERCHANTABILITY, OR FITNESS FOR A
--     PARTICULAR PURPOSE OF SAID MATERIAL.
--*
--
-- OBJECTIVE:
--      Check that the tag of an object of a tagged type is preserved by
--      type conversion and parameter passing.
--
-- TEST DESCRIPTION:
--      The fact that the tag of an object is not changed is verified by
--      making dispatching calls to primitive operations, and confirming that
--      the proper body is executed. Objects of both specific and class-wide
--      types are checked. 
--
--      The dispatching calls are made in two contexts. The first is a
--      straightforward dispatching call made from within a class-wide
--      operation. The second is a redispatch from within a primitive
--      operation.
--
--      For the parameter passing case, the initial class-wide and specific
--      objects are passed directly in calls to the class-wide and primitive
--      operations. The redispatch is accomplished by initializing a local
--      class-wide object in the primitive operation to the value of the
--      formal parameter, and using the local object as the actual in the
--      (re)dispatching call.
--
--      For the type conversion case, the initial class-wide object is assigned
--      a view conversion of an object of a specific type:
--
--         type T is tagged ...
--         type DT is new T with ...
--
--         A : DT;
--         B : T'Class := T(A); -- Despite conversion, tag of B is that of DT.
--
--      The class-wide object is then passed directly in calls to the
--      class-wide and primitive operations. For the initial object of a
--      specific type, however, a view conversion of the object is passed,
--      forcing a non-dispatching call in the primitive operation case. Within
--      the primitive operation, a view conversion of the formal parameter to
--      a class-wide type is then used to force a (re)dispatching call.
--
--      For the type conversion and parameter passing case, a combining of
--      view conversion and parameter passing of initial specific objects are 
--      called directly to the class-wide and primitive operations. 
--
--
-- CHANGE HISTORY:
--      28 Jun 95   SAIC    Initial prerelease version.
--      23 Apr 96   SAIC    Added use C390007_0 in the main.
--
--!

package C390007_0 is

   type Call_ID_Kind is (None, Parent_Outer,  Parent_Inner,
                               Derived_Outer, Derived_Inner);

   type Root_Type is abstract tagged null record;

   procedure Outer_Proc (X : in out Root_Type) is abstract;
   procedure Inner_Proc (X : in out Root_Type) is abstract;

   procedure ClassWide_Proc (X : in out Root_Type'Class);

end C390007_0;


     --==================================================================--


package body C390007_0 is

   procedure ClassWide_Proc (X : in out Root_Type'Class) is
   begin
      Inner_Proc (X);
   end ClassWide_Proc;

end C390007_0;


     --==================================================================--


package C390007_0.C390007_1 is

   type Param_Parent_Type is new Root_Type with record
      Last_Call : Call_ID_Kind := None;
   end record;

   procedure Outer_Proc (X : in out Param_Parent_Type);
   procedure Inner_Proc (X : in out Param_Parent_Type);

end C390007_0.C390007_1;


     --==================================================================--


package body C390007_0.C390007_1 is

   procedure Outer_Proc (X : in out Param_Parent_Type) is
   begin
      X.Last_Call := Parent_Outer;
   end Outer_Proc;

   procedure Inner_Proc (X : in out Param_Parent_Type) is
   begin
      X.Last_Call := Parent_Inner;
   end Inner_Proc;

end C390007_0.C390007_1;


     --==================================================================--


package C390007_0.C390007_1.C390007_2 is

   type Param_Derived_Type is new Param_Parent_Type with null record;

   procedure Outer_Proc (X : in out Param_Derived_Type);
   procedure Inner_Proc (X : in out Param_Derived_Type);

end C390007_0.C390007_1.C390007_2;


     --==================================================================--


package body C390007_0.C390007_1.C390007_2 is

   procedure Outer_Proc (X : in out Param_Derived_Type) is
      Y : Root_Type'Class := X;
   begin
      Inner_Proc (Y);  -- Redispatch.
      Root_Type'Class (X) := Y;
   end Outer_Proc;

   procedure Inner_Proc (X : in out Param_Derived_Type) is
   begin
      X.Last_Call := Derived_Inner;
   end Inner_Proc;

end C390007_0.C390007_1.C390007_2;


     --==================================================================--


package C390007_0.C390007_3 is

   type Convert_Parent_Type is new Root_Type with record
      First_Call  : Call_ID_Kind := None;
      Second_Call : Call_ID_Kind := None;
   end record;

   procedure Outer_Proc (X : in out Convert_Parent_Type);
   procedure Inner_Proc (X : in out Convert_Parent_Type);

end C390007_0.C390007_3;


     --==================================================================--


package body C390007_0.C390007_3 is

   procedure Outer_Proc (X : in out Convert_Parent_Type) is
   begin
      X.First_Call := Parent_Outer;
      Inner_Proc (Root_Type'Class(X));  -- Redispatch.
   end Outer_Proc;

   procedure Inner_Proc (X : in out Convert_Parent_Type) is
   begin
      X.Second_Call := Parent_Inner;
   end Inner_Proc;

end C390007_0.C390007_3;


     --==================================================================--


package C390007_0.C390007_3.C390007_4 is

   type Convert_Derived_Type is new Convert_Parent_Type with null record;

   procedure Outer_Proc (X : in out Convert_Derived_Type);
   procedure Inner_Proc (X : in out Convert_Derived_Type);

end C390007_0.C390007_3.C390007_4;


     --==================================================================--


package body C390007_0.C390007_3.C390007_4 is

   procedure Outer_Proc (X : in out Convert_Derived_Type) is
   begin
      X.First_Call := Derived_Outer;
      Inner_Proc (Root_Type'Class(X));  -- Redispatch.
   end Outer_Proc;

   procedure Inner_Proc (X : in out Convert_Derived_Type) is
   begin
      X.Second_Call := Derived_Inner;
   end Inner_Proc;

end C390007_0.C390007_3.C390007_4;


     --==================================================================--


with C390007_0.C390007_1.C390007_2;
with C390007_0.C390007_3.C390007_4;
use  C390007_0;

with Report;
procedure C390007 is
begin
   Report.Test ("C390007", "Check that the tag of an object of a tagged " &
                "type is preserved by type conversion and parameter passing");


   --
   -- Check that tags are preserved by parameter passing:
   --

   Parameter_Passing_Subtest:
   declare
      Specific_A  : C390007_0.C390007_1.C390007_2.Param_Derived_Type;
      Specific_B  : C390007_0.C390007_1.C390007_2.Param_Derived_Type;

      ClassWide_A : C390007_0.C390007_1.Param_Parent_Type'Class := Specific_A;
      ClassWide_B : C390007_0.C390007_1.Param_Parent_Type'Class := Specific_B;

      use C390007_0.C390007_1;
      use C390007_0.C390007_1.C390007_2;
   begin

      Outer_Proc (Specific_A);         
      if Specific_A.Last_Call /= Derived_Inner then
         Report.Failed ("Parameter passing: tag not preserved in call to " &
                        "primitive operation with specific operand");
      end if;

      C390007_0.ClassWide_Proc (Specific_B);
      if Specific_B.Last_Call /= Derived_Inner then
         Report.Failed ("Parameter passing: tag not preserved in call to " &
                        "class-wide operation with specific operand");
      end if;

      Outer_Proc (ClassWide_A);        
      if ClassWide_A.Last_Call /= Derived_Inner then
         Report.Failed ("Parameter passing: tag not preserved in call to " &
                        "primitive operation with class-wide operand");
      end if;

      C390007_0.ClassWide_Proc (ClassWide_B);
      if ClassWide_B.Last_Call /= Derived_Inner then
         Report.Failed ("Parameter passing: tag not preserved in call to " &
                        "class-wide operation with class-wide operand");
      end if;

   end Parameter_Passing_Subtest;


   --
   -- Check that tags are preserved by type conversion:
   --

   Type_Conversion_Subtest:
   declare
      Specific_A  : C390007_0.C390007_3.C390007_4.Convert_Derived_Type;
      Specific_B  : C390007_0.C390007_3.C390007_4.Convert_Derived_Type;

      ClassWide_A : C390007_0.C390007_3.Convert_Parent_Type'Class :=
                    C390007_0.C390007_3.Convert_Parent_Type(Specific_A);
      ClassWide_B : C390007_0.C390007_3.Convert_Parent_Type'Class :=
                    C390007_0.C390007_3.Convert_Parent_Type(Specific_B);

      use C390007_0.C390007_3;
      use C390007_0.C390007_3.C390007_4;
   begin

      Outer_Proc (Convert_Parent_Type(Specific_A));
      if (Specific_A.First_Call  /= Parent_Outer)  or
         (Specific_A.Second_Call /= Derived_Inner)
      then
         Report.Failed ("Type conversion: tag not preserved in call to " &
                        "primitive operation with specific operand");
      end if;

      Outer_Proc (ClassWide_A);   
      if (ClassWide_A.First_Call  /= Derived_Outer) or
         (ClassWide_A.Second_Call /= Derived_Inner)
      then
         Report.Failed ("Type conversion: tag not preserved in call to " &
                        "primitive operation with class-wide operand");
      end if;

      C390007_0.ClassWide_Proc (Convert_Parent_Type(Specific_B));
      if (Specific_B.Second_Call /= Derived_Inner) then
         Report.Failed ("Type conversion: tag not preserved in call to " &
                        "class-wide operation with specific operand");
      end if;

      C390007_0.ClassWide_Proc (ClassWide_B);
      if (ClassWide_A.Second_Call /= Derived_Inner) then
         Report.Failed ("Type conversion: tag not preserved in call to " &
                        "class-wide operation with class-wide operand");
      end if;

   end Type_Conversion_Subtest;


   --
   -- Check that tags are preserved by type conversion and parameter passing:
   --

   Type_Conversion_And_Parameter_Passing_Subtest:
   declare
      Specific_A  : C390007_0.C390007_1.C390007_2.Param_Derived_Type;
      Specific_B  : C390007_0.C390007_1.C390007_2.Param_Derived_Type;

      use C390007_0.C390007_1;
      use C390007_0.C390007_1.C390007_2;
   begin

      Outer_Proc (Param_Parent_Type (Specific_A));   
      if Specific_A.Last_Call /= Parent_Outer then
         Report.Failed ("Type conversion and parameter passing: tag not " &
                        "preserved in call to primitive operation with "  &
                        "specific operand");
      end if;

      C390007_0.ClassWide_Proc (Param_Parent_Type (Specific_B));
      if Specific_B.Last_Call /= Derived_Inner then
         Report.Failed ("Type conversion and parameter passing: tag not " &
                        "preserved in call to class-wide operation with "  &
                        "specific operand");
      end if;

   end Type_Conversion_And_Parameter_Passing_Subtest;


   Report.Result;

end C390007;
